/*
 * ccvelic.h
 *
 *  Created on: 2/10/2012
 *      Author: cvan680
 */

#ifndef CCVELIC_H_
#define CCVELIC_H_

#include "voreen/core/processors/imageprocessor.h"
#include "voreen/core/processors/renderprocessor.h"
#include "voreen/core/properties/optionproperty.h"
#include "modules/flowreen/processors/flowreenprocessor.h"
#include "modules/flowreen/datastructures/simpletexture.h"

#include "voreen/core/ports/renderport.h"
#include "voreen/core/properties/filedialogproperty.h"
#include "voreen/core/properties/vectorproperty.h"
#include "voreen/core/properties/buttonproperty.h"
#include "tgt/shadermanager.h"

using tgt::TextureUnit;
using std::string;

namespace voreen {

class CcveLIC : public ImageProcessor, public FlowreenProcessor {
public:
	CcveLIC();
	~CcveLIC();

    // virtual constructor
    virtual Processor* create() const;

    // documentary functions
    virtual std::string getClassName() const { return "CcveLIC";       }
    virtual std::string getCategory() const  { return "Image Processing";      }
    virtual CodeState getCodeState() const   { return CODE_STATE_EXPERIMENTAL; }

protected:

    enum SliceAlignment {
    	// :-)
        PLANE_XY = 2,   /** view from the volume's front to back (negative z-axis) */
        PLANE_XZ = 1,   /** view from the volume's bottom to top (negative y-axis) */
        PLANE_ZY = 0    /** view from the volume's right to left (negative x-axis) */
    };

    enum TextureZoom {
        ZOOM_FULL_SIZE = 0,
        ZOOM_1X = 1,
        ZOOM_2X = 2,
        ZOOM_4X = 4,
        ZOOM_8X = 8
    };

    virtual void setDescriptions() {
        setDescription("LIC processor");
    }

    // actual rendering code
    virtual void process();

    /// loads the shader
    virtual void initialize() throw (VoreenException);

    /// frees the shader
    virtual void deinitialize() throw (VoreenException);
    virtual void compile();

    TextureZoom zoom_;

    tgt::Texture* flow2DTexture_;

    /**
     * Prepares the OpenGL machine for orthographic rendering by pushing
     * all attributes, setting up the ModelView and the Projection matrices,
     * setting the viewport and disabeling the depth test.
     * You MUST call <code>endOrthographicRendering()</code> after EVERY
     * call to <code>beginOrthographicRendering</code>.
     * This is basically used by any texture generation technique.
     *
     * @param   viewport    dimensions of the viewport (usually the size
     *                      of the texture to be generated)
     */
    void beginOrthographicRendering(const tgt::ivec2& viewport) const;

    /**
     * Restores all the settings which have been modified by calling
     * <code>beginOrthographicRendering()</code>. This concerns the
     * all attributes, the depth test, the ModelView and the Projecteion
     * matrix.
     */
    void endOrthographicRendering() const;

    /**
     * Generates a tgt::Texture from the specified render target with the given texture size.
     * The texture contains 4 color channels (GL_RGBA) stored as floats (GL_FLOAT).
     * The caller has to free the texture using delete, afterwards.
     *
     * @param   rendeport   RenderPort object containing the image.
     * @param   textureSize Size of the texture. Note that this size must be less or equal to
     *                      the actual size of the render target!
     */
    tgt::Texture* copyTargetToTexture(RenderPort& renderport, const tgt::vec2& textureSize) const;
    tgt::Shader* shader_;

private:
	VolumePort inport0_;
    RenderPort inport1_;
    RenderPort outport_;

    RenderPort privatePort1_;
    RenderPort privatePort2_;
    PortGroup portGroup_;

    IntProperty kernelSizeProp_;
    IntProperty pixelSamplingProp_;
    BoolProperty useAdaptiveKernelSizeProp_;
    OptionProperty<SliceAlignment>* alignmentProp_;
    FloatVec2Property thresholdProp_;
    IntProperty sliceIndexProp_;

    /** the current 2D texture containing the flow image */
    tgt::Texture* sliceTexture_;

    /** the currently used slice alignment */
    SliceAlignment alignment_;

    /** permutation of the components of the flow according to selected slice alignment */
    tgt::ivec3 permutation_;


    // this is where the magic happens
    //tgt::Texture* renderLIC(Flow2D flow2D);


    // functions
    float getTextureScalingFactor(const tgt::vec2& viewportSize, const tgt::vec2& textureSize);

    void onThresholdChange();
    void onSliceAlignmentChange();
    tgt::ivec3 getCoordinatePermutation(const SliceAlignment& alignment);


    float* pixels;
    float* colours;


    // mouse event handling
    EventProperty<CcveLIC>* mouseEventProp_;
    EventProperty<CcveLIC>* mouseClickProp_;
    void mouseEvent(tgt::MouseEvent* e);
    tgt::ivec2 mouseCurPos2D_;
    bool mouseDown_;

    int ORIGINAL_COUNTER;
    int counter_;

    bool loadShader(const std::string& vertexShaderName, const std::string& fragmentShaderName);
    bool rebuildShader();
    std::string generateShaderHeader();
    void prepareFlowTexture2D(const Flow2D& flow2D);

    void uploadTextureToShader(tgt::Texture* tex);

    GLuint createTexture(GLubyte* data, tgt::ivec2 dims, GLint internalformat, GLenum format);
    void bindTexture(GLuint id, string uniform, TextureUnit texunit);
};

} // namespace

#endif /* CCVELIC_H_ */
